Category management
Business scenario
Categories in Qoyod organize products into a hierarchy that appears on invoices, inventory reports, and the chart of accounts. Before your integration creates a product in Qoyod, the category that product belongs to must already exist — Qoyod does not create categories automatically when a product references one.
This use case covers the integrated system to Qoyod direction for category setup. When you synchronize a product catalog from an e-commerce platform, POS system, or ERP into Qoyod, your integration must first walk the category tree from the integrated system, check which categories already exist in Qoyod, and create any that are missing. The result is a Qoyod category id for each category — an integer your integration stores and passes as category_id when creating products.
If this step is skipped, product creation requests that include a category_id will fail with a 422 Unprocessable Entity error. Products created without a category_id are uncategorized, which makes reporting in Qoyod less useful and may cause accounting misalignment if your merchant's chart of accounts depends on category structure.
When to use this
Use this when:
- You are about to create products in Qoyod and those products belong to named categories in the integrated system.
- You are performing an initial catalog import and need to establish Qoyod's category tree before any products are created.
- You need to look up an existing category's Qoyod
idto pass ascategory_idon a product creation or update request. - You are adding a new category to the integrated system and need to mirror that category in Qoyod.
Do not use this when:
- You need to update a category's name or description — that is
PUT /2.0/categories/{id}, which is out of scope for this page. - You need to delete a category — no delete endpoint exists for categories in the Qoyod API.
- You are creating products that do not belong to any category — omit
category_idfrom the product creation request and skip this use case.
Prerequisites
- A valid OAuth 2.0 access token for the Qoyod account you are integrating with. An API key is also accepted by the categories endpoints.
- The category tree from your integrated system, including the name and parent relationships for each category you intend to mirror in Qoyod.
- A mechanism in your integration to store the Qoyod category
idreturned for each category you create or retrieve. This integer is required ascategory_idwhen creating products. - If you are creating child categories, the parent category must already exist in Qoyod and its
idmust be available before you create the child.
Sequence diagram
Step-by-step
1. Check whether the category already exists
Before creating a category, query Qoyod to see if it already exists. Use the q[name_cont] query parameter to filter by name.
curl -X GET "https://api.qoyod.com/2.0/categories?q[name_cont]=Electronics" \
-H "Authorization: Bearer {your_access_token}"
A 200 OK response contains a categories array. Inspect it for a matching name. If found, store the id and skip to the next category.
{
"categories": [
{
"id": 14,
"name": "Electronics",
"description": null,
"parent_id": null,
"created_at": "2026-01-10T08:00:00.000Z",
"updated_at": "2026-01-10T08:00:00.000Z"
}
]
}
A 404 Not Found response means no categories matched. The response body is a plain string — not a JSON object. Proceed to create the category.
"We could not retrieve your categories, we found nothing."
2. Create the missing category
Send a POST request with the category wrapped in a category object. The name field is effectively required — the server returns 422 Unprocessable Entity if it is omitted, even though the spec schema does not mark it required.
curl -X POST https://api.qoyod.com/2.0/categories \
-H "Authorization: Bearer {your_access_token}" \
-H "Content-Type: application/json" \
-d '{
"category": {
"name": "Electronics",
"description": "Consumer electronics and accessories"
}
}'
For a child category, include parent_id:
{
"category": {
"name": "Mobile Phones",
"description": "Smartphones and accessories",
"parent_id": 14
}
}
3. Store the returned category ID
A successful creation returns 201 Created with the new category under a category key.
{
"category": {
"id": 27,
"name": "Mobile Phones",
"description": "Smartphones and accessories",
"parent_id": 14,
"created_at": "2026-05-18T10:00:00.000Z",
"updated_at": "2026-05-18T10:00:00.000Z"
}
}
Store id (27 here) against the corresponding category in your integrated system. Pass it as category_id when creating products.
4. Repeat top-down through the category tree
Work parent-before-child through the hierarchy. A child category requires a valid parent_id, so the parent must exist and its id must be stored before the child is created.
Field mapping
This table covers the fields relevant to POST /2.0/categories. For the full request and response schemas, see the categories reference.
| Integrated system concept | Qoyod field | Required | Notes |
|---|---|---|---|
| Category name | name | Yes (server-enforced) | String. The server returns 422 Unprocessable Entity with name: can't be blank if omitted. The spec schema does not mark this field required — see Edge cases. |
| Category description | description | No | Free-text string. Omit if your integrated system has no equivalent. |
| Parent category reference | parent_id | No | Integer Qoyod category id. Omit for top-level categories. The parent must already exist in Qoyod before you set this value. |
The GET /2.0/categories and GET /2.0/categories/{id} responses include id, name, description, parent_id, created_at, and updated_at. There is no level or depth field in the response — your integration must track hierarchy depth itself if needed.
The id returned in any response is the value you store and pass as category_id on product creation and update requests.
Verification
After a POST /2.0/categories returns 201 Created:
-
Confirm the response body contains a
categoryobject with a non-null integerid. Ifidis absent, do not treat the creation as successful — log the full response and investigate. -
Store that
idbefore making any further requests. It cannot be recovered from the response after the request completes, and re-querying by name carries the risk of matching a different category if names are not unique. -
Optionally, confirm the category exists in Qoyod by sending a
GET /2.0/categories/{id}request using the storedid:
curl -X GET "https://api.qoyod.com/2.0/categories/27" \
-H "Authorization: Bearer {your_access_token}"
A 200 OK response confirms the category is retrievable. Compare the returned name and parent_id against what your integration sent to detect any silent data transformation.
Verification with GET /2.0/categories/{id} is optional for routine operation. It is most useful during initial integration testing and when diagnosing unexpected behavior in downstream product creation.
Error scenarios
These are the error responses your integration should handle for the endpoints in this use case. For the complete error catalog, see the error handling reference.
422 Unprocessable Entity — name missing
Returned by POST /2.0/categories when the name field is omitted from the request body.
{
"errors": {
"name": ["can't be blank"]
}
}
Resolution: Add the name field to the category object in the request body before retrying. Do not retry without correcting the request — the server will return 422 again.
422 Unprocessable Entity — invalid parent_id
Returned by POST /2.0/categories when parent_id references a category that does not exist in Qoyod.
{
"errors": {
"parent_id": ["does not exist"]
}
}
Resolution: Verify that the parent category has been successfully created in Qoyod and that you are using the correct integer id. Create the parent first if it is missing.
401 Unauthorized
Returned when the access token is missing, expired, or invalid.
Resolution: Refresh your OAuth 2.0 access token and retry the request.
:::warning Limitation The Qoyod API does not support category deletion. Once a category is created, it cannot be removed via the API. Plan your category tree carefully before importing. :::